package com.app.view_controller.custom_view;

import com.app.alarm.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v4.view.GestureDetectorCompat;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

public class DayChooserWithFont extends View implements GestureDetector.OnGestureListener {

	private static final String TAG = "ToggleBUttonWithFont";
	private static final boolean DEBUG = true;
	private static final float DEFAULT_TEXT_SIZE = 20;
	private int textDistance;
	private GestureDetectorCompat gDetector;
	private Context mContext;
	private OnDayCheckedListener mCheckListener;
	private Day[] mDayArray;
	private int colorOn, colorOff;

	public DayChooserWithFont(Context context) {
		super(context);
		mContext = context;
		init(null);
	}

	public DayChooserWithFont(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DayChooserWithFont, 0, 0);
		init(array);
	}

	public DayChooserWithFont(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		mContext = context;
		TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DayChooserWithFont, 0, 0);
		init(array);
	}

	private void init(TypedArray array) {

		mDayArray = new Day[8];
		for (int i = 1; i < mDayArray.length; i++) {
			mDayArray[i] = new Day();
			mDayArray[i].day = i;
		}

		// Gesture detector
		gDetector = new GestureDetectorCompat(mContext, this);

		// initialize the text of the days
		try {
			if (array != null && array.getText(R.styleable.DayChooserWithFont_textSunday) != null)
				mDayArray[1].text = (String) array.getText(R.styleable.DayChooserWithFont_textSunday);
			else
				mDayArray[1].text = "SUN";
			if (array != null && array.getText(R.styleable.DayChooserWithFont_textMonday) != null)
				mDayArray[2].text = (String) array.getText(R.styleable.DayChooserWithFont_textMonday);
			else
				mDayArray[2].text = "MON";
			if (array != null && array.getText(R.styleable.DayChooserWithFont_textTuesday) != null)
				mDayArray[3].text = (String) array.getText(R.styleable.DayChooserWithFont_textTuesday);
			else
				mDayArray[3].text = "TUE";
			if (array != null && array.getText(R.styleable.DayChooserWithFont_textWednesday) != null)
				mDayArray[4].text = (String) array.getText(R.styleable.DayChooserWithFont_textWednesday);
			else
				mDayArray[4].text = "WEN";
			if (array != null && array.getText(R.styleable.DayChooserWithFont_textThursday) != null)
				mDayArray[5].text = (String) array.getText(R.styleable.DayChooserWithFont_textThursday);
			else
				mDayArray[5].text = "THU";
			if (array != null && array.getText(R.styleable.DayChooserWithFont_textFriday) != null)
				mDayArray[6].text = (String) array.getText(R.styleable.DayChooserWithFont_textFriday);
			else
				mDayArray[6].text = "FRI";
			if (array != null && array.getText(R.styleable.DayChooserWithFont_textSaturday) != null)
				mDayArray[7].text = (String) array.getText(R.styleable.DayChooserWithFont_textSaturday);
			else
				mDayArray[7].text = "SAT";

			// Set the text dimension for the days.
			for (int i = 1; i < mDayArray.length; i++)
				mDayArray[i].textPaint.setTextSize(array.getDimension(R.styleable.DayChooserWithFont_textSize,
						TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, DEFAULT_TEXT_SIZE, getResources().getDisplayMetrics())));

			// Set the text color when it's off.
			for (int i = 1; i < mDayArray.length; i++)
				colorOff = array.getColor(R.styleable.DayChooserWithFont_textColorOff, getResources().getColor(android.R.color.holo_red_light));

			// Set the text color when it's on.
			for (int i = 1; i < mDayArray.length; i++)
				colorOn = array.getColor(R.styleable.DayChooserWithFont_textColorOn, getResources().getColor(android.R.color.holo_green_light));

			// Retrieve the value for every day.
			mDayArray[1].isChecked = array.getBoolean(R.styleable.DayChooserWithFont_isSundayChecked, false);
			mDayArray[2].isChecked = array.getBoolean(R.styleable.DayChooserWithFont_isMondayChecked, false);
			mDayArray[3].isChecked = array.getBoolean(R.styleable.DayChooserWithFont_isTuesdayChecked, false);
			mDayArray[4].isChecked = array.getBoolean(R.styleable.DayChooserWithFont_isWednesdayChecked, false);
			mDayArray[5].isChecked = array.getBoolean(R.styleable.DayChooserWithFont_isThursdayChecked, false);
			mDayArray[6].isChecked = array.getBoolean(R.styleable.DayChooserWithFont_isFridayChecked, false);
			mDayArray[7].isChecked = array.getBoolean(R.styleable.DayChooserWithFont_isSaturdayChecked, false);

		} catch (Exception e) {
			if (DEBUG)
				Log.d(TAG, "Error retriving xml attributes " + e);
		} finally {
			array.recycle();
		}
	}

	/**
	 * 
	 * @author Nick Listener used to know when it's clicked on a day
	 * 
	 */
	public interface OnDayCheckedListener {
		/**
		 * 
		 * @param v
		 *            The view that triggers this callback.
		 * @param day
		 *            The day clicked.
		 * @param ischecked
		 *            The value for the clicked day.
		 */
		public void onDayCheckedChanged(View v, int day, boolean isChecked);
	}

	/**
	 * 
	 * @author Nick Private class that holds all the information needed for a
	 *         day
	 * 
	 */
	private static class Day {
		@SuppressWarnings("unused")
		int day;
		String text;
		TextPaint textPaint;
		Rect textBounds;
		boolean isChecked;

		private Day() {
			text = "";
			textPaint = new TextPaint();
			textBounds = new Rect();
			isChecked = false;
		}

	}

	@Override
	public int getSuggestedMinimumWidth() {
		Rect bounds = new Rect();
		int minWidth = 0;
		// for every day
		for (int i = 1; i < mDayArray.length; i++) {
			// get the text width
			mDayArray[i].textPaint.getTextBounds(mDayArray[i].text, 0, mDayArray[i].text.length(), bounds);
			// and then sums every width
			minWidth += (bounds.right - bounds.left);
		}
		return minWidth + getPaddingLeft() + getPaddingRight();
	}

	@Override
	public int getSuggestedMinimumHeight() {
		return (int) (getPaddingTop() + getPaddingBottom() + mDayArray[1].textPaint.getTextSize());

	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int msWidth = MeasureSpec.getSize(widthMeasureSpec);
		int msHeight = MeasureSpec.getSize(heightMeasureSpec);
		int wMode = MeasureSpec.getMode(widthMeasureSpec);
		int hMode = MeasureSpec.getMode(heightMeasureSpec);
		int finalWidth = 0;
		int finalHeight = 0;
		// Handle the width
		switch (wMode) {
		// wrap-content case
		case MeasureSpec.AT_MOST:
			finalWidth = Math.min(getSuggestedMinimumWidth(), msWidth);
			break;
		// Match_parent, user imposed dimensions,...
		case MeasureSpec.EXACTLY:
			finalWidth = msWidth;
			break;
		// What the fuck you want
		case MeasureSpec.UNSPECIFIED:
			finalWidth = getSuggestedMinimumWidth();
			break;
		}
		// Handle the height
		switch (hMode) {
		// wrap-content case
		case MeasureSpec.AT_MOST:
			finalHeight = Math.min(getSuggestedMinimumHeight(), msHeight);
			break;
		// Match_parent, user imposed dimensions,...
		case MeasureSpec.EXACTLY:
			finalHeight = msHeight;
			break;
		// What the fuck you want
		case MeasureSpec.UNSPECIFIED:
			finalHeight = getSuggestedMinimumHeight();
			break;
		}
		// Method that must be called or an exception it's thrown.
		setMeasuredDimension(finalWidth, finalHeight);
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		int paddingLeft = getPaddingLeft();
		int paddingRight = getPaddingRight();

		// The total amount of pixel occupied by the text
		int textSpace = 0;
		Rect bounds = new Rect();
		for (int i = 1; i < mDayArray.length; i++) {
			mDayArray[i].textPaint.getTextBounds(mDayArray[i].text, 0, mDayArray[i].text.length(), bounds);
			textSpace += bounds.width();
		}

		// The space between 2 words
		textDistance = Math.max(0, (w - paddingLeft - paddingRight - textSpace) / 6);

		// Calculate the bounds for every day of the week
		mDayArray[1].textPaint.getTextBounds(mDayArray[1].text, 0, mDayArray[1].text.length(), bounds);
		mDayArray[1].textBounds.left = paddingLeft;
		mDayArray[1].textBounds.right = mDayArray[1].textBounds.left + bounds.width();
		mDayArray[1].textBounds.top = (int) ((h - mDayArray[1].textPaint.getTextSize()) / 2);
		mDayArray[1].textBounds.bottom = (int) (mDayArray[1].textBounds.top + mDayArray[1].textPaint.getTextSize());
		for (int i = 2; i < mDayArray.length; i++) {
			mDayArray[i].textPaint.getTextBounds(mDayArray[i].text, 0, mDayArray[i].text.length(), bounds);
			// The next day starts at the end of the previous one + the distance
			// between every day
			mDayArray[i].textBounds.left = mDayArray[i - 1].textBounds.right + textDistance;
			mDayArray[i].textBounds.right = mDayArray[i].textBounds.left + bounds.width();
			mDayArray[i].textBounds.top = (int) ((h - mDayArray[i].textPaint.getTextSize()) / 2);
			mDayArray[i].textBounds.bottom = (int) (mDayArray[i].textBounds.top + mDayArray[i].textPaint.getTextSize());
			// if (DEBUG)
			// Log.d(TAG, "mtextbounds left right top bottom " +
			// mTextBounds[i].left + " " + mTextBounds[i].right
			// + " " + mTextBounds[i].top + " " + mTextBounds[i].bottom);
		}

	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		for (int i = 1; i < mDayArray.length; i++) {
			// Set the color of the text.
			if (mDayArray[i].isChecked) {
				mDayArray[i].textPaint.setColor(colorOn);
				mDayArray[i].textPaint.setFakeBoldText(true);
				mDayArray[i].textPaint.setFlags(TextPaint.UNDERLINE_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
			} else {
				mDayArray[i].textPaint.setColor(colorOff);
				mDayArray[i].textPaint.setFakeBoldText(false);
				mDayArray[i].textPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
			}
			canvas.drawText(mDayArray[i].text, mDayArray[i].textBounds.left, mDayArray[i].textBounds.bottom, mDayArray[i].textPaint);
		}
	}

	/**
	 * 
	 * @param day
	 *            The day chosen.
	 * @param isChecked
	 *            Boolean value representing if the day should be activated or
	 *            not.
	 */
	public void setDayChecked(int day, boolean isChecked) {
		mDayArray[day].isChecked = isChecked;
		invalidate();
	}

	/**
	 * 
	 * @param day
	 *            The day chosen.
	 * @return The value of the button for the chosen day.
	 */
	public boolean isDayChecked(int day) {
		return mDayArray[day].isChecked;
	}

	/**
	 * Method used to change the color of the on text. the color must be in the
	 * #xxyyzz format.
	 * 
	 * @param color
	 *            The color chosen.
	 */
	public void setTextOnColor(int color) {
		colorOn = color;
		invalidate();
	}

	/**
	 * Method used to change the color of the off text. the color must be in the
	 * #xxyyzz format.
	 * 
	 * @param color
	 *            The color chosen.
	 */
	public void setTextOffColor(int color) {
		colorOff = color;
		invalidate();
	}

	/**
	 * 
	 * @return The on text color in the #xxyyzz format
	 */
	public int getTextOnColor() {
		return colorOn;
	}

	/**
	 * 
	 * @return The off text color in the #xxyyzz format.
	 */
	public int getTextOffColor() {
		return colorOff;
	}

	/**
	 * Register a callback to be invoked when a day is clicked.
	 * 
	 * @param callback
	 *            The callback that will run.
	 */
	public void setOnDayCheckedListener(OnDayCheckedListener callback) {
		mCheckListener = (OnDayCheckedListener) callback;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// Set the detector that will handle the touch events.
		return gDetector.onTouchEvent(event);
		
	}

	@Override
	public boolean onSingleTapUp(MotionEvent e) {
		if (DEBUG)
			Log.d(TAG, "on single tap");
		int xPoint = (int) e.getX();
		int yPoint = (int) e.getY();
		for (int i = 1; i < mDayArray.length; i++) {
			// Search what day has been touched
			if (mDayArray[i].textBounds.contains(xPoint, yPoint)) {
				// If the listener has been set by setOnDayCheckListener, launch
				// the method
				mDayArray[i].isChecked = !mDayArray[i].isChecked;
				if (mCheckListener != null)
					mCheckListener.onDayCheckedChanged(this, i, mDayArray[i].isChecked);
				invalidate();
				break;
			}
		}

		return true;
	}

	@Override
	public boolean onDown(MotionEvent e) {
		if (DEBUG)
			Log.d(TAG, "onDowncalled");
		return true;
	}

	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
		// DO NOTHING
		return false;
	}

	@Override
	public void onLongPress(MotionEvent e) {
		// DO NOTHING
	}

	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
		//DO NOTHING
		return false;
	}

	@Override
	public void onShowPress(MotionEvent e) {
		// DO NOTHING
	}

}
